﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Common.Extension;
using log4net;
using Common.Model;
using Newtonsoft.Json;
using Spider.Mode;

namespace Spider.Spider
{
    public class DxwSpider
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(DxwSpider));
        
        private const string Bkurl =
                @"http://api.quchaogu.com/app/subject/billboard?device_id=a869763025534267&isOpen=1&sortType=0&filter_date=0&filter_classify=&from=dxw&apiversion=5.7&device_id=a869763025534267"
            ;

        private static readonly int PageCount = 10;


        /// <summary>
        /// 获取短线王的板块分类列表
        /// </summary>
        public static List<ConceptClassify> GetClassify()
        {
            //获取板块分类列表
            var mode = JsonConvert.DeserializeObject<DxwMode>(GetJson(Bkurl));

            var filterClassifyItems = mode.data.filter_classify;

            var conceptList = new List<ConceptClassify>();

            //循环列表，获取分类列表对应的板块集合
            filterClassifyItems.ForEach(
                calssify =>
                {
                    var conceptClassify = new ConceptClassify
                    {
                        ClassifyName = calssify.t,
                        Concept = new List<Concept>()
                    };
                    conceptList.Add(conceptClassify);

                    //根据分类列表名称获取对应板块集合
                    var url =
                        "http://api.quchaogu.com/app/subject/billboard?device_id=a869763025534267&isOpen=1&sortType=0&filter_date=0&filter_classify=" +
                        HttpUtility.UrlEncode(calssify.v) + "&from=dxw&apiversion=5.7&device_id=a869763025534267";

                    var json = GetJson(url);
                    var dxwMode = JsonConvert.DeserializeObject<DxwMode>(json);

                    //组装数据模型
                    foreach (var rankItemItems in dxwMode.data.rank)
                    {
                        var enumerable = rankItemItems.Select(m => new Concept
                        {
                            ConceptCode = m.para.code,
                            ConceptName = m.name
                        });
                        conceptClassify.Concept.AddRange(enumerable);
                    }
                });

            return conceptList;
        }

        public static Dictionary<string, List<DxwEvent>> GetEvents(DateTime startTime)
        {
            var dictionary = new ConcurrentDictionary<string, List<DxwEvent>>();

            List<ConceptClassify> conceptClassifies = GetClassify().Where(m => "按大类".Equals(m.ClassifyName)).ToList();


            var enumerable = conceptClassifies.Partition(10).ToList();
            foreach (var classifies in enumerable)
            {
                var tasks = new List<Task>();
                var conceptDictionary = GetConceptDictionary(classifies);
                //获取EventId
                foreach (var pair in conceptDictionary)
                {
                    var startNew = Task.Factory.StartNew(() =>
                    {
                        var getEventIdUrl = "http://api.quchaogu.com/app/event/check?device_id=a869763025534267&code="
                                            + pair.Value
                                            + "&device_id=a869763025534267&apiversion=5.7&device_id=a869763025534267";
                        var eventIdJson = "";
                        try
                        {
                            eventIdJson = GetJson(getEventIdUrl);
                        }
                        catch (Exception e)
                        {
                            try
                            {
                                eventIdJson = GetJson(getEventIdUrl);
                            }
                            catch (Exception c)
                            {
                                Log.Info(c);
                                return;
                            }
                        }

                        var eventMode = JsonConvert.DeserializeObject<DxwEventIdMode>(eventIdJson);
                        var eventId = eventMode.data.event_id;

                        if ("".Equals(eventId) || null == eventId)
                            return;

                        //创建事件列表
                        var dxwEvents = new List<DxwEvent>();

                        //根据EventId获取Event列表
                        for (var i = 1; i < 200; i++)
                        {
                            var getEventListUrl =
                                "http://api.quchaogu.com/event/hangye/list?device_id=a869763025534267&filter=0&event_id="
                                + eventId
                                + "&pagecount="
                                + PageCount
                                + "&apiversion=5.7&page="
                                + i
                                + "&device_id=a869763025534267";

                            var eventListJson = "";
                            
                            try
                            {
                                eventListJson = GetJson(getEventListUrl);
                            }
                            catch (Exception e)
                            {
                                try
                                {
                                    eventListJson = GetJson(getEventListUrl);
                                }
                                catch (Exception exception)
                                {
                                    Log.Info(exception);
                                    continue;
                                }
                            }
                            
                            var dxwEventListMode = JsonConvert.DeserializeObject<DxwEventListMode>(eventListJson);

                            var dxwEventList = dxwEventListMode.data.item_list;
                            if (dxwEventList.Count == 0)
                                break;

                            //获取Event详情
                            var events = dxwEventList.Where(item => !item.head_list[0].t.Contains("盘中")).Select(item
                                    =>
                                {
                                    var getEventUrl = "http://api.quchaogu.com/app/event/eventDetail?item_id="
                                                      + item.param.item_id
                                                      + "&apiversion=5.7&device_id=a869763025534267";
                                    var eventJson = "";
                                    try
                                    {
                                        eventJson = GetJson(getEventUrl);
                                    }
                                    catch (Exception e)
                                    {
                                        try
                                        {
                                            eventJson = GetJson(getEventUrl);
                                        }
                                        catch (Exception exception)
                                        {
                                            Log.Info(exception);
                                            return new DxwEvent();
                                        }
                                    }

                                    var dxwEventMode = JsonConvert.DeserializeObject<DxwEventMode>(eventJson);
                                    var title = dxwEventMode.data.base_info.title;
                                    var time = dxwEventMode.data.base_info.time;
                                    var desc = dxwEventMode.data.base_info.desc;
                                    var eventType = dxwEventMode.data.base_info.sub_event;

                                    var stockList = dxwEventMode.data.stock.list.Select(s => s.name).ToList();

                                    if (stockList.Count > 5)
                                        stockList = stockList.GetRange(0, 5);

                                    var stocks = new StringBuilder();
                                    stockList.ForEach(code =>
                                    {
                                        stocks.Append(code);
                                        stocks.Append(",");
                                    });
                                    if (stocks.Length > 0)
                                        stocks.Remove(stocks.Length - 1, 1);

                                    var block = pair.Key;
                                    return new DxwEvent()
                                    {
                                        Block = block,
                                        Content = desc,
                                        Title = title,
                                        EventId = pair.Value + "_" + eventId + "_" + item.head_list[0].param.item_id,
                                        EventType = eventType,
                                        SiteTime = DateTime.Parse(time),
                                        Stocks = stocks.ToString(),
                                        CrawlingTime = DateTime.Now
                                    };
                                }
                            ).ToList();
                            events = events.Where(m => null != m.EventId).ToList();
                            events = events.Where(m =>
                                    (string.IsNullOrEmpty(m.EventType) ||
                                     (!m.EventType.Contains("价格") && !m.EventType.Contains("期货"))))
                                .ToList();
                            if (events.Any(m => m.SiteTime <= startTime))
                            {
                                events = events.Where(m => m.SiteTime > startTime).ToList();
                                dxwEvents.AddRange(events);
                                break;
                            }

                            dxwEvents.AddRange(events);
                            if (dxwEventList.Count < PageCount)
                                break;
                        }
                        dictionary.TryAdd(pair.Key, dxwEvents);
                    });

                    tasks.Add(startNew);
                }
                Task.WaitAll(tasks.ToArray());
            }
            return dictionary.ToDictionary(m => m.Key, n => n.Value);
        }

        public static Dictionary<string, List<DxwEvent>> GetAllEvents()
        {
            return GetEvents(DateTime.Parse("2001-01-01"));
//            return GetEvents(DateTime.Parse("2018-03-04"));
        }

        /// <summary>
        /// 板块分类列表转换为键值对，key=name,value=code
        /// </summary>
        private static Dictionary<string, string> GetConceptDictionary(List<ConceptClassify> conceptClassifies)
        {
            var conceptDictionary = new Dictionary<string, string>();

            conceptClassifies.ForEach(cons =>
                cons.Concept.ForEach(c =>
                {
                    if (!conceptDictionary.ContainsKey(c.ConceptName))
                        conceptDictionary.Add(c.ConceptName, c.ConceptCode);
                }));

            return conceptDictionary;
        }


        /// <summary>
        /// 组装请求，由于短线王APP会根据UserAgent和Cookie确定版本并且返回不同的数据，因此必须带上相应字段
        /// </summary>
        private static HttpWebRequest GetRequest(string url)
        {
            var request = (HttpWebRequest) WebRequest.Create(url);

            request.Method = WebRequestMethods.Http.Get;

            request.ContentType = "application/json;charset=utf-8";
            request.UserAgent = "DxwApp:1.7.0.27 | android:5.1 | Meizu:m1 metal | sc:360,640 | did:a869763025534267";

            var cookieContainer = new CookieContainer(3);
            request.CookieContainer = cookieContainer;

            var cookie = new Cookie("web_uinfo", "%7B%22uactime%22%3A1515139618%7D");
            request.CookieContainer.Add(new Uri("http://api.quchaogu.com/"), cookie);

            cookie = new Cookie("vistor_uuid", "51990107686080739545656");
            request.CookieContainer.Add(new Uri("http://api.quchaogu.com/"), cookie);

            cookie = new Cookie("web_qtstr",
                "7%253A3%253A1161120864%253Aa869763025534267%253A6%253A1515137301%253A22d4db999352996");
            request.CookieContainer.Add(new Uri("http://api.quchaogu.com/"), cookie);


            return request;
        }

        /// <summary>
        /// 获取json
        /// </summary>
        private static string GetJson(string url)
        {
            var httpWebRequest = GetRequest(url);

            var response = (HttpWebResponse) httpWebRequest.GetResponse();
            var myResponseStream = response.GetResponseStream();
            var myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
            var retString = myStreamReader.ReadToEnd();

            myStreamReader.Close();
            myResponseStream.Close();

            return retString;
        }
    }
}